//
// Created by 邹嘉旭 on 2025/8/8.
//

#include "interface/gs1.h"

#include "as_entity.h"
#include "define.h"
#include "interface/air.h"
#include "interface/ground.h"

static field_desc gs1_sac_rqst_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 28, "AS UA", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_sac_rqst_desc = {"GS1 SAC REQUEST", gs1_sac_rqst_fields};

static field_desc gs1_sac_resp_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 28, "AS UA", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_sac_resp_desc = {"GS1 SAC RESPONSE", gs1_sac_resp_fields};

static field_desc gs1_initial_as_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_set, 28, "AS UA", NULL},
    {ft_set, 12, "GS SAC", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_dl_str, 0, "SDU", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_init_as_desc = {"GS1 INITIAL AS", gs1_initial_as_fields};

static field_desc gs1_snf_upload_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_dl_str, 0, "SDU", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_snf_pkt_desc = {"GS1 SNF UPLOAD", gs1_snf_upload_fields};

static field_desc gs1_ho_rqst_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_set, 12, "GSS SAC", NULL},
    {ft_set, 12, "GST SAC", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_ho_rqst_desc = {"GS1 HO RQST", gs1_ho_rqst_fields};

static field_desc gs1_as_exit_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_as_exit_desc = {"GS1 AS EXIT", gs1_as_exit_fields};

static field_desc gs1_data_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_set, 8, "IDENTIFY", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_dl_str, 0, "SDU", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_data_desc = {"GS1 DATA", gs1_data_fields};


static field_desc gs1_ho_rqst_ack_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_set, 9, "CO", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_ho_rqst_ack_desc = {"GSG HO RQST ACK", gs1_ho_rqst_ack_fields};

static field_desc gs1_ho_complete_fields[] = {
    {ft_set, 4, "TYPE", NULL},
    {ft_set, 12, "AS SAC", NULL},
    {ft_set, 12, "GS SAC", NULL},
    {ft_pad, 0, "PAD", NULL},
    {ft_end, 0, NULL, NULL},
};
struct_desc_t gs1_ho_complete_desc = {"GSG HO COMPLETE", gs1_ho_complete_fields};




static l_err recv_gs1_sac_rqst(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_init_as(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_snf_download(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_msmf_snf_down(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_ho_rqst(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_as_exit(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_data(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_ho_rqst_ack(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);
static l_err recv_gs1_ho_complete(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt);


size_t gs1_format_count = 15;
cn_format_desc_t gs1_format_descs[] = {
    {0, NULL, 0},
    {GS1_SAC_RQST, &gs1_sac_rqst_desc, "GS1 SAC RQST", sizeof(gs1_sac_rqst_t), 4, NULL, recv_gs1_sac_rqst, NULL, free},
    {GS1_SAC_RESP, &gs1_sac_resp_desc, "GS1 SAC RESP", sizeof(gs1_sac_resp_t), 6, default_cn_send_handler, NULL, NULL, free},
    {GS1_INIT_AS, &gs1_init_as_desc, "GS1 INIT AS", sizeof(gs1_init_as_t), 0, NULL, recv_gs1_init_as, NULL, free_gs1_init_as},
    {GS1_SNF_UPLOAD, &gs1_snf_pkt_desc, "GS1 SNF UPLOAD", sizeof(gs1_snf_pkt_t), 0, default_cn_send_handler, NULL, NULL, free_gs1_snf_pkt},
    {GS1_SNF_DOWNLOAD, &gs1_snf_pkt_desc, "GS1 SNF DOWNLOAD", sizeof(gs1_snf_pkt_t), 0, NULL, recv_gs1_snf_download, NULL, free_gs1_snf_pkt},
    {GS1_KEY_TRANS, &gs1_snf_pkt_desc, "GS1 KEY TRANS", sizeof(gs1_snf_pkt_t), 0, default_cn_send_handler, NULL, NULL, free_gs1_snf_pkt},
    {GS1_HO_REQUEST, &gs1_ho_rqst_desc, "GS1 HO RQST", sizeof(gs1_ho_rqst_t), 5, NULL, recv_ho_rqst, NULL, free},
    {GS1_HO_REQUEST_ACK, &gs1_ho_rqst_ack_desc, "GS1 HO RQST ACK", sizeof(gs1_ho_rqst_ack_t), 4, default_cn_send_handler, recv_gs1_ho_rqst_ack, NULL,  free},
    {GS1_HO_COMPLETE, &gs1_ho_complete_desc, "GS1 HO COMPLETE", sizeof(gs1_ho_complete_t), 4, NULL, recv_gs1_ho_complete, NULL, free},
    {GS1_UP_UPLOAD_TRANSPORT, &gs1_snf_pkt_desc, "GS1 MSMF SNF UP", sizeof(gs1_snf_pkt_t), 0, default_cn_send_handler, NULL, NULL, free_gs1_snf_pkt},
    {GS1_UP_DOWNLOAD_TRANSPORT, &gs1_snf_pkt_desc, "GS1 MSMF SNF DOWN", sizeof(gs1_snf_pkt_t), 0, NULL, recv_gs1_msmf_snf_down, NULL, free_gs1_snf_pkt},
    {GS1_AS_EXIT, &gs1_as_exit_desc, "GS1 AS EXIT", sizeof(gs1_as_exit_t), 2, NULL, recv_gs1_as_exit, NULL, free},
    {GS1_DATA_UP, &gs1_data_desc, "GS1 DATA", sizeof(gs1_data_t), 0, default_cn_send_handler, NULL, NULL, free_gs1_data},
    {GS1_DATA_DOWN, &gs1_data_desc, "GS1 DATA", sizeof(gs1_data_t), 0, NULL, recv_gs1_data, NULL, free_gs1_data},
};


static l_err recv_gs1_sac_rqst(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_sac_rqst_t *rqst = NULL;
    if ((rqst = parse_sdu(in_buf, desc->f_desc, desc->struct_size)) == NULL) {
        log_error("Parse SDU failed!");
        if (rqst)    desc->free_func(rqst);
        return LD_ERR_INVALID;
    }
    if (!has_as_uenode(net_ele->as_map, rqst->AS_UA)) {
        as_entity_t *new_as = init_as_entity(rqst->AS_UA, 0, propt->peer_sac, ELEMENT_GSG, net_ele);
        // 设定AS当前接口的回复propt
        // set_as_propt(new_as, INTERFACE_GS1, propt);
        set_as_enode(net_ele->as_map, new_as);

        as_entity_t *as = get_as_uenode_by_UA(net_ele->as_map, rqst->AS_UA);
        if (!as) {
            cn_log_error(net_ele->element_tag, INTERFACE_GS1, "No such AS: %d.", rqst->AS_UA);
            desc->free_func(rqst);
            return LD_ERR_INVALID;
        }

        if (in_state(&as->gsg_sm, "GSG_INITIAL")) {
            if (change_state(&as->gsg_sm, EV_DEFAULT,
                             &(fsm_event_data_t){
                                 &gsg_fsm_events[GSG_SAC_ALLOCING], NULL
                             }) != LD_OK) {
                cn_log_error( net_ele->element_tag, INTERFACE_G1, "cant change state correctly");
                desc->free_func(rqst);
                return LD_ERR_INVALID;
                             }
        }

        g1_sac_rqst_t g1_sac_rqst = {
            .GTYPE = G1_SAC_RQST,
            .VERSION = CN_VERSION,
            .AS_UA = rqst->AS_UA,
        };

        cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_SAC_RQST);
        if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
                net_ele,
                &g1_sac_rqst,
                send_desc,
                get_propt(net_ele, INTERFACE_G1, 0),
                INTERFACE_G1
            ) != LD_OK) {
            cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
            desc->free_func(rqst);
            return LD_ERR_NULL;
            }
    } else {

        as_entity_t *as = get_as_uenode_by_UA(net_ele->as_map, rqst->AS_UA);
        if (!as) {
            cn_log_error(net_ele->element_tag, INTERFACE_GS1, "No such AS: %d.", rqst->AS_UA);
            desc->free_func(rqst);
            return LD_ERR_INVALID;
        }

        gs1_sac_resp_t gs1_sac_resp = {
            .TYPE = GS1_SAC_RESP,
            .AS_UA = as->UA,
            .AS_SAC = as->SAC,
        };

        cn_format_desc_t *send_desc = &gs1_format_descs[GS1_SAC_RESP];
        if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
                net_ele,
                &gs1_sac_resp,
                send_desc,
                get_propt(net_ele, INTERFACE_GS1, as->current_client_peer_sac),
                INTERFACE_GS1
            ) != LD_OK) {
            cn_log_error(net_ele->element_tag, INTERFACE_GS1, "Failed to send");
            desc->free_func(rqst);
            return LD_ERR_NULL;
        }

        cn_log_error(net_ele->element_tag, INTERFACE_GS1, "Can not repeatly access AS. UA: %d ; SAC : %d; propt: %p", as->UA, as->SAC, propt);
    }

    desc->free_func(rqst);

    return LD_OK;
}

static l_err recv_gs1_init_as(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_init_as_t *init = calloc(1, sizeof(gs1_init_as_t));
    PARSE_DSTR_PKT(in_buf, init, sdu, gs1_init_as_desc, GS1_AS_INI_HEAD_LEN, 0)

    as_entity_t *as = get_as_uenode_by_UA(net_ele->as_map, init->AS_UA);

    if (as) {
        g1_g3_init_as_t g1_init_as = {
            .GTYPE = G1_INIT_AS,
            .VERSION = CN_VERSION,
            .AS_SAC = as->SAC,
            .AS_UA = as->UA,
            .GS_SAC = init->GS_SAC,
            .element_type = 0xF,
            .sdu = init_buffer_unptr(),
        };
        CLONE_TO_CHUNK(*g1_init_as.sdu, init->sdu->ptr, init->sdu->len);



        cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_INIT_AS);
        if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
                net_ele,
                &g1_init_as,
                send_desc,
                get_propt(net_ele, INTERFACE_G1, 0),
                INTERFACE_G1
            ) != LD_OK) {
            cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
            desc->free_func(init);
            free_buffer(g1_init_as.sdu);
            return LD_ERR_NULL;
        }

        free_buffer(g1_init_as.sdu);
    }else {

        as_entity_t *new_as = init_as_entity(init->AS_UA, 0, propt->peer_sac, ELEMENT_GSG, net_ele);
        // 设定AS当前接口的回复propt
        // set_as_propt(new_as, INTERFACE_GS1, propt);
        set_as_enode(net_ele->as_map, new_as);
        // desc->free_func(init);
        // cn_log_error( net_ele->element_tag, INTERFACE_GS1, "No such AS : %d", init->AS_SAC);
        // return LD_ERR_INVALID;
    }

    desc->free_func(init);
    return LD_OK;
}

static l_err recv_gs1_snf_download(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_snf_pkt_t *download = calloc(1, sizeof(gs1_snf_pkt_t));
    PARSE_DSTR_PKT(in_buf, download, sdu, gs1_snf_pkt_desc, GS1_PKT_HEAD_LEN, 0)

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, download->AS_SAC);

    if (as) {
        g1_g3_snf_pkt_t g1_download = {
            .GTYPE = G1_SNF_DOWNLOAD,
            .VERSION = CN_VERSION,
            .AS_SAC = as->SAC,
            .element_type = 0xF,
            .sdu = init_buffer_unptr(),
        };
        CLONE_TO_CHUNK(*g1_download.sdu, download->sdu->ptr, download->sdu->len);

        cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_SNF_DOWNLOAD);
        if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
                net_ele,
                &g1_download,
                send_desc,
                get_propt(net_ele, INTERFACE_G1, 0),
                INTERFACE_G1
            ) != LD_OK) {
            cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
            desc->free_func(download);
            free_buffer(g1_download.sdu);
            return LD_ERR_NULL;
            }

        free_buffer(g1_download.sdu);
    }else {
        desc->free_func(download);
        cn_log_error( net_ele->element_tag, INTERFACE_GS1, "No such AS");
        return LD_ERR_INVALID;
    }

    desc->free_func(download);
    return LD_OK;
}

static l_err recv_gs1_msmf_snf_down(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_snf_pkt_t *down = calloc(1, sizeof(gs1_snf_pkt_t));
    PARSE_DSTR_PKT(in_buf, down, sdu, gs1_snf_pkt_desc, GS1_PKT_HEAD_LEN, 0)

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, down->AS_SAC);

    // 解析SNF, 并把AS ip 存入as中
    sn_session_est_resp_t *est_resp = parse_sdu(down->sdu, &sn_session_est_resp_desc, sizeof(sn_session_est_resp_t));
    set_as_as_ip(as, (char *)est_resp->IP_AS->ptr);

    free_sn_session_est_resp(est_resp);

    if (as) {
        client_interface_t *cli_int = get_client_interface(net_ele, INTERFACE_G1U);

        g1_g5_bearer_est_t g1_bearer = {
            .GTYPE = G1_DATA_BEARER_EST_RESP,
            .VERSION = CN_VERSION,
            .AS_SAC = as->SAC,
            .element_type = 0xF,
            .snf_msg = init_buffer_unptr(),
            .IP = init_buffer_unptr(),
            .port = cli_int->local_port,
        };

        struct in6_addr addr;
        inet_pton(AF_INET6, cli_int->local_addr_v6, &addr);
        CLONE_TO_CHUNK(*g1_bearer.IP, addr.__in6_u.__u6_addr8, GEN_ADDRLEN);
        CLONE_TO_CHUNK(*g1_bearer.snf_msg, down->sdu->ptr, down->sdu->len);


        cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_DATA_BEARER_EST_RESP);
        if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
                net_ele,
                &g1_bearer,
                send_desc,
                get_propt(net_ele, INTERFACE_G1, 0),
                INTERFACE_G1
            ) != LD_OK) {
            cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
            desc->free_func(down);
            free_buffer(g1_bearer.snf_msg);
            free_buffer(g1_bearer.IP);
            return LD_ERR_NULL;
            }

        free_buffer(g1_bearer.snf_msg);
        free_buffer(g1_bearer.IP);
    }else {
        desc->free_func(down);
        cn_log_error( net_ele->element_tag, INTERFACE_GS1, "No such AS");
        return LD_ERR_INVALID;
    }

    desc->free_func(down);
    return LD_OK;
}

static l_err recv_gs1_as_exit(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_as_exit_t *exit = NULL;
    if ((exit = parse_sdu(in_buf, desc->f_desc, desc->struct_size)) == NULL) {
        log_error("Parse SDU failed!");
        if (exit)    desc->free_func(exit);
        return LD_ERR_INVALID;
    }

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, exit->AS_SAC);
    if (!as) {
        cn_log_error(net_ele->element_tag, INTERFACE_GS1, "No such AS: %d.", exit->AS_SAC);
        desc->free_func(exit);
        return LD_ERR_INVALID;
    }

    g1_g5_as_release_exit_t g1_exit = {
        .GTYPE = G1_AS_EXIT,
        .VERSION = CN_VERSION,
        .AS_SAC = as->SAC,
    };

    cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_AS_EXIT);
    if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
            net_ele,
            &g1_exit,
            send_desc,
            get_propt(net_ele, INTERFACE_G1, 0),
            INTERFACE_G1
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
        desc->free_func(exit);
        return LD_ERR_NULL;
    }


    desc->free_func(exit);
    return LD_OK;
}

static l_err recv_gs1_data(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_data_t *gs1_data = calloc(1, sizeof(gs1_data_t));

    PARSE_DSTR_PKT(in_buf, gs1_data, sdu, gs1_data_desc, GS1_DATA_HEAD_LEN, 0 )

    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, gs1_data->AS_SAC);
    if (!as) {
        cn_log_error(net_ele->element_tag, INTERFACE_GS1, "No such AS: %d.", gs1_data->AS_SAC);
        desc->free_func(gs1_data);
        return LD_ERR_INVALID;
    }

    if (default_cn_forward_handler(net_ele, gs1_data->sdu,
                                   get_propt(net_ele, INTERFACE_G1U, 0)
                                   , INTERFACE_G1U)) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1U, "Failed to send");
        desc->free_func(gs1_data);
        return LD_ERR_NULL;
    }

    desc->free_func(gs1_data);
    return LD_OK;
}

static l_err recv_ho_rqst(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_ho_rqst_t *gs1_rqst = NULL;

    if ((gs1_rqst = parse_sdu(in_buf, desc->f_desc, desc->struct_size)) == NULL) {
        log_error("Parse SDU failed!");
        if (gs1_rqst)    desc->free_func(gs1_rqst);
        return LD_ERR_INVALID;
    }


    as_entity_t *as = get_as_uenode_by_SAC(net_ele->as_map, gs1_rqst->AS_SAC);
    if (!as) {
        cn_log_error(net_ele->element_tag, INTERFACE_GS1, "No such AS: %d.", gs1_rqst->AS_SAC);
        desc->free_func(gs1_rqst);
        return LD_ERR_INVALID;
    }

    g1_ho_rqst_t g1_rqst = {
        .GTYPE = G1_HANDOVER_REQUEST,
        .VERSION = CN_VERSION,
        .AS_SAC = as->SAC,
        .AS_UA = as->UA,
        .GSS_SAC = gs1_rqst->GSS_SAC,
        .GST_SAC = gs1_rqst->GST_SAC,
    };

    cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_HANDOVER_REQUEST);

    if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
            net_ele,
            &g1_rqst,
            send_desc,
            get_propt(net_ele, INTERFACE_G1, 0),
            INTERFACE_G1
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
        desc->free_func(gs1_rqst);
        return LD_ERR_NULL;
    }

    desc->free_func(gs1_rqst);

    return LD_OK;
}

static l_err recv_gs1_ho_rqst_ack(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_ho_rqst_ack_t *ack = NULL;

    if ((ack = parse_sdu(in_buf, desc->f_desc, desc->struct_size)) == NULL) {
        log_error("Parse SDU failed!");
        if (ack)    desc->free_func(ack);
        return LD_ERR_INVALID;
    }


    g1_ho_rqst_ack_t g1_ack = {
        .GTYPE = G1_HANDOVER_REQUEST_ACK,
        .AS_SAC = ack->AS_SAC,
        .NEXT_CO = ack->NEXT_CO,
    };

    cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_HANDOVER_REQUEST_ACK);
    if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
            net_ele,
            &g1_ack,
            send_desc,
            get_propt(net_ele, INTERFACE_G1, 0),
            INTERFACE_G1
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
        desc->free_func(ack);
        return LD_ERR_NULL;
    }

    desc->free_func(ack);
    return LD_OK;
}

static l_err recv_gs1_ho_complete(net_element_t *net_ele, cn_format_desc_t *desc, buffer_t *in_buf, element_propt_t *propt) {
    gs1_ho_complete_t *complete = NULL;

    if ((complete = parse_sdu(in_buf, desc->f_desc, desc->struct_size)) == NULL) {
        log_error("Parse SDU failed!");
        return LD_ERR_INVALID;
    }


    g1_g3_g5_as_st_chg_t chg = {
        .GTYPE = G1_AS_STATE_CHANGE,
        .VERSION = CN_VERSION,
        .AS_SAC = complete->AS_SAC,
        .GS_SAC = complete->GS_SAC,
        .STATE = SWITCH,
    };

    cn_format_desc_t *send_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, G1_AS_STATE_CHANGE);
    if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
            net_ele,
            &chg,
            send_desc,
            get_propt(net_ele, INTERFACE_G1, 0),
            INTERFACE_G1
        ) != LD_OK) {
        cn_log_error(net_ele->element_tag, INTERFACE_G1, "Failed to send");
        desc->free_func(complete);
        return LD_ERR_NULL;
    }

    free(complete);
    return LD_OK;
}
